﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Collections;
using System.Linq;
//using System.Xml.Linq;
using System.Threading;
using System.IO;

using CommonUtils;
using TConst = TERP.Constants;
using TError = TERP.Errors;


namespace TERP.Utils
{
	public class CProcessException
	{
		public static DataSet Process(
			ref DataSet mdsFinal
			, Exception exc
			, string strErrorCode
			, params object[] arrobjErrorParams
			)
		{
			// Process:
			if (CMyException.IsMyException(exc))
			{
				CMyDataSet.SetErrorCode(ref mdsFinal, CMyException.GetErrorCode(exc));
				CMyDataSet.AppendErrorParams(ref mdsFinal, CMyException.GetErrorParams(exc));
			}
			else
			{
				CMyDataSet.SetErrorCode(ref mdsFinal, strErrorCode);
				CMyDataSet.AppendErrorParams(ref mdsFinal, arrobjErrorParams);
				if (exc.Data != null)
				{
					foreach (object objDataKey in exc.Data.Keys)
					{
						CMyDataSet.AppendErrorParams(ref mdsFinal, string.Format("ExcData.{0}", objDataKey), string.Format("{0}", exc.Data[objDataKey]));
					}
				}
				CMyDataSet.AppendErrorParams(
					ref mdsFinal
					, "ExceptionContents", string.Format("{0}\r\n{1}", exc.Message, exc.StackTrace)
					);
			}

			// Always return Bad:
			mdsFinal.AcceptChanges();
			return mdsFinal;
		}
		public static DataSet Process(
			ref DataSet mdsFinal
			, WSTLog log
			, string strGwUserCodeForLog
			, string strGwPasswordForLog
			, string strFunctionName
			, string strAppTid
			, string strAppTDateTime
			, string strAppServiceCode
			, string strAppUserCode
			, string strLanguageCode
			, string strRemark
			)
		{
			// Temp:
			if (!string.Equals(CMyDataSet.GetErrorCode(mdsFinal), TError.Error.NoError))
			{
				object[] arrobjCouple = CMyDataSet.GetErrorParams(mdsFinal);
				if (arrobjCouple == null) arrobjCouple = new object[0];
				object[] arrobjTriple = new object[arrobjCouple.Length / 2 * 3];
				for (int i = 0, j = 0; i < arrobjCouple.Length; i += 2, j += 3)
				{
					arrobjTriple[j] = arrobjCouple[i];
					arrobjTriple[j + 1] = "";
					arrobjTriple[j + 2] = arrobjCouple[i + 1];
				}

				// Write log:
				log.WriteLogAsync(
					strGwUserCodeForLog // strGwUserCodeForLog
					, strGwPasswordForLog // strGwPasswordForLog
					, strAppTid // strAppTid
					, strAppServiceCode // strAppServiceCode
					, strAppUserCode // strAppUserCode
					, strAppTDateTime // strAppTDateTime
					, Convert.ToString(CMyDataSet.GetErrorCode(mdsFinal)) // strAppErrorCode
					, strFunctionName // strAppLogType1
					, "RESPONSE" // strAppLogType2
					, "ERROR" // strAppLogType3
					, strLanguageCode // strAppLanguageCode
					, Convert.ToString(CMyDataSet.GetRemark(mdsFinal)) // strAppRemark
					, arrobjTriple // arrobjParamsTriple
					);
			}

			// Return:
			mdsFinal.AcceptChanges();
			return mdsFinal;
		}
	}

	public class CUtils
	{
		public static string TidNext(object strTidOrg, ref int n)
		{
			return string.Format("{0}.{1}", strTidOrg, n++);
		}
		public static ArrayList ParamsCouple2ParamsTriple(ArrayList alParamsCouple, int nInsertPos, object objInsert)
		{
			// Process:
			ArrayList alTripleParams = new ArrayList();
			if (nInsertPos == 0)
			{
				for (int i = 0; i < alParamsCouple.Count; i += 2)
				{
					alTripleParams.AddRange(new object[] { objInsert, alParamsCouple[i], alParamsCouple[i + 1] });
				}
			}
			else if (nInsertPos == 1)
			{
				for (int i = 0; i < alParamsCouple.Count; i += 2)
				{
					alTripleParams.AddRange(new object[] { alParamsCouple[i], objInsert, alParamsCouple[i + 1] });
				}
			}
			else
			{
				for (int i = 0; i < alParamsCouple.Count; i += 2)
				{
					alTripleParams.AddRange(new object[] { alParamsCouple[i], alParamsCouple[i + 1], objInsert });
				}
			}

			// Return Good:
			return alTripleParams;
		}
		public static Hashtable ParseParamList(string strParamList, string strSeparatorEntry, string strSeparatorDetail, bool bUpperCaseKey)
		{
			// Init:
			Hashtable htResult = new Hashtable();
			if (strParamList == null || string.Equals(strParamList, "")) return htResult;
			string[] arrstrEntry = strParamList.Split(new string[] { strSeparatorEntry }, StringSplitOptions.None);

			// Process:
			for (int i = 0; i < arrstrEntry.Length; i++)
			{
				string[] arrstrParam = arrstrEntry[i].Split(new string[] { strSeparatorDetail }, StringSplitOptions.None);
				if (bUpperCaseKey)
				{
					htResult.Add(arrstrParam[0].ToUpper(), arrstrParam[1]);
				}
				else
				{
					htResult.Add(arrstrParam[0], arrstrParam[1]);
				}
			}

			// Return Good:
			return htResult;
		}
		public static string ParamsCouple2String(object[] arrobjParamsCouple, string strSeparatorEntry, string strSeparatorDetail)
		{
			// Init:
			if (arrobjParamsCouple == null || arrobjParamsCouple.Length <= 0) return "";
			StringBuilder strbd = new StringBuilder(1000);

			// Process:
			for (int i = 0; i < arrobjParamsCouple.Length; i += 2)
			{
				strbd.AppendFormat("{0}{1}{2}{3}"
					, arrobjParamsCouple[i]
					, strSeparatorDetail
					, arrobjParamsCouple[i + 1]
					, strSeparatorEntry
					);
			}

			// Return Good:
			return strbd.ToString(0, strbd.Length - strSeparatorEntry.Length); // Remove the last strSeparatorEntry.
		}
		public static string ParamsTriple2String(object[] arrobjParamsTriple, string strSeparatorEntry)
		{
			// Init:
			if (arrobjParamsTriple == null || arrobjParamsTriple.Length <= 0) return "";
			StringBuilder strbd = new StringBuilder(1000);

			// Process:
			for (int i = 0; i < arrobjParamsTriple.Length; i += 3)
			{
				strbd.AppendFormat("{0}{1}{2}{3}"
					, arrobjParamsTriple[i]
					, arrobjParamsTriple[i + 1]
					, arrobjParamsTriple[i + 2]
					, strSeparatorEntry
					);
			}

			// Return Good:
			return strbd.ToString(0, strbd.Length - strSeparatorEntry.Length); // Remove the last strSeparatorEntry.
		}
		public static string StandardizeMonth(object strMonth)
		{
			return (string.Format("{0}-01", Convert.ToDateTime(strMonth).ToString("yyyy-MM")));
		}
		public static object StandardizeMonthOrDBNull(object strMonth)
		{
			if (string.Format("{0}", strMonth).Trim().Length < 1) return DBNull.Value;
			return StandardizeMonth(strMonth);
		}
		public static string StandardizeDate(object strDate)
		{
			return (Convert.ToDateTime(strDate).ToString("yyyy-MM-dd"));
		}
		public static object StandardizeDateOrDBNull(object strDate)
		{
			if (string.Format("{0}", strDate).Trim().Length < 1) return DBNull.Value;
			return StandardizeDate(strDate);
		}

		public static DataSet MyDSEncode(DataSet mds)
		{
			// Check:
			if (mds == null || CMyDataSet.IsCompress(mds)) return mds;

			// Init:
			DataSet mdsNew = CMyDataSet.NewMyDataSet(CMyDataSet.GetTid(mds), CMyDataSet.GetDigitalSignature(mds));
			CMyDataSet.SetErrorCode(ref mdsNew, CMyDataSet.GetErrorCode(mds));
			CMyDataSet.SetCompressStatus(ref mdsNew, true);

			// Process:
			string strPlain = XmlUtils.DataSet2Xml(mds);
			byte[] arrbytePlain = StringUtils.String2ArrayBytes(Encoding.Unicode, strPlain);
			byte[] arrbyteCompressedData = CompressUtils.CompressGZip(arrbytePlain);
			DataTable dtCompressedData = new DataTable("dtCompressedData");
			dtCompressedData.Columns.Add("CompressedData", typeof(object));
			dtCompressedData.Rows.Add(arrbyteCompressedData);
			DataUtils.MoveDataTable(ref mdsNew, ref dtCompressedData);
			mdsNew.AcceptChanges();

			// Return Good:
			return mdsNew;
		}

		public static DataSet MyDSDecode(DataSet mds)
		{
			// Check:
			if (mds == null || !CMyDataSet.IsCompress(mds)) return mds;

			// Init:
			byte[] arrbyteCompressedData = (byte[])mds.Tables["dtCompressedData"].Rows[0][0];
			byte[] arrbytePlain = CompressUtils.DecompressGZip(arrbyteCompressedData);
			string strPlain = StringUtils.ArrayBytes2String(Encoding.Unicode, arrbytePlain);
			DataSet mdsNew = XmlUtils.Xml2DataSet(strPlain);

			// Return Good:
			return mdsNew;
		}
	}

	public class CConnectionManager
	{ 
		#region // Constructors and Destructors:
		private object _objLockForSessionManager = new object();
		private CSessionManager _smManager = null;
		private int _nTimeOutMilliseconds = 0; // Milliseconds.
		private string _strConfig_GWUserCode = "";
		private string _strConfig_GWPassword = "";
		private string _strErrCodeWhenGatewayAuthenticateFailed = "";
		private string _strErrCodeWhenSessionNotFound = "";
		private string _strErrCodeWhenSessionExpired;
		public CConnectionManager(
			int nSessionTimeOut
			, string strConfig_GWUserCode
			, string strConfig_GWPassword
			, string strErrCodeWhenGatewayAuthenticateFailed
			, string strErrCodeWhenSessionNotFound
			, string strErrCodeWhenSessionExpired
			)
		{
			_smManager = new CSessionManager();
			_nTimeOutMilliseconds = nSessionTimeOut;
			_strConfig_GWUserCode = strConfig_GWUserCode;
			_strConfig_GWPassword = strConfig_GWPassword;
			_strErrCodeWhenGatewayAuthenticateFailed = strErrCodeWhenGatewayAuthenticateFailed;
			_strErrCodeWhenSessionNotFound = strErrCodeWhenSessionNotFound;
			_strErrCodeWhenSessionExpired = strErrCodeWhenSessionExpired;
		}
		#endregion

		#region // Public members:
		public void CheckGatewayAuthentication(
			ref ArrayList alParamsCoupleError
			, string strGwUserCode
			, string strGwPassword
			)
		{
			// Check GatewayAuthentication:
			if (!StringUtils.StringEqualIgnoreCase(strGwUserCode, _strConfig_GWUserCode)
				|| !StringUtils.StringEqual(strGwPassword, _strConfig_GWPassword)
				)
			{
				throw CMyException.Raise(
					_strErrCodeWhenGatewayAuthenticateFailed
					, null
					, alParamsCoupleError.ToArray()
					);
			}
		}
		public string AddSession(
			string strPartnerCode
			, string strPartnerUserCode
			, string strLanguageCode
			, string strUserCode
			, string strOtherInfo
			)
		{
			return _smManager.SessionAdd(
				strPartnerCode
				, strPartnerUserCode
				, strLanguageCode
				, strUserCode
				, strOtherInfo
				);
		}
		public DataRow GetSessionInfo(
			ref ArrayList alParamsCoupleError
			, string strSessionId
			)
		{
			DataRow drSession = _smManager.GetSessionInfo(strSessionId);
			if (drSession == null)
			{
				throw CMyException.Raise(
					_strErrCodeWhenSessionNotFound
					, null
					, alParamsCoupleError.ToArray()
					);
			}
			return drSession;
		}
		public void CheckSessionExpired(
			ref ArrayList alParamsCoupleError
			, string strSessionId
			, DataRow drSession
			)
		{
			// Check ExpiredSession:
			if (DateTimeUtils.Minus(DateTime.Now, drSession["DateTimeLastAccess"]).TotalMilliseconds > _nTimeOutMilliseconds)
			{
				_smManager.SessionRemove(strSessionId); // Remove ExpiredSession.
				alParamsCoupleError.AddRange(new object[]{
						"DateTimeLastAccess", drSession["DateTimeLastAccess"]
						, "TimeoutMillisecond", drSession["TimeoutMillisecond"]
						, "DateTimeNow", DateTime.Now
						});
				throw CMyException.Raise(
					_strErrCodeWhenSessionExpired
					, null
					, alParamsCoupleError.ToArray()
					);
			}
		}
		public void CleanSessionExpired()
		{
			DataTable dtSessions = _smManager.GetAllSessionInfo().Copy();
			for (int i = 0; i < dtSessions.Rows.Count; i++)
			{
				string strSessionId = Convert.ToString(dtSessions.Rows[i]["SessionId"]);
				if (DateTimeUtils.Minus(DateTime.Now, dtSessions.Rows[i]["DateTimeLastAccess"]).TotalMilliseconds > _nTimeOutMilliseconds)
				{
					_smManager.SessionRemove(strSessionId);
				}
			}
		}
		public void CheckAllCondition(
			ref ArrayList alParamsCoupleError
			, string strGwUserCode
			, string strGwPassword
			, string strSessionId
			, out DataRow drSession
			)
		{
			// Init:
			drSession = null;

			// Check GatewayAuthentication:
			CheckGatewayAuthentication(
				ref alParamsCoupleError // alParamsCoupleError
				, strGwUserCode // strGwUserCode
				, strGwPassword // strGwPassword
				);

			// Check Session:
			drSession = GetSessionInfo(
				ref alParamsCoupleError // alParamsCoupleError
				, strSessionId // strSessionId
				);
			string strPartnerCode = Convert.ToString(drSession["PartnerCode"]);

			//// Check ExpiredSession:
			//CheckSessionExpired(
			//    ref alParamsCoupleError // alParamsCoupleError
			//    , strSessionId // strSessionId
			//    , drSession // drSession
			//    );

			// Reset LastAccess:
			_smManager.SessionSetLastAccess(strSessionId);
		}
		#endregion
	}

}
